package com.king.aspect;

import com.king.annotation.SysLog;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MemberSignature;
import org.aspectj.lang.reflect.MethodSignature;
import org.aspectj.weaver.ast.Var;
import org.springframework.cglib.reflect.MethodDelegate;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * 日志切面
 *
 * @packageNme com.king.aspect
 * @Author: jinguoguang
 * @Date: 2024/5/27 14:58
 * @Version: v1.0.0
 **/
@Aspect
@Slf4j
@Component
public class SysLogAspect {
    /**
     * 请求开始时间
     */
    ThreadLocal<Long> startTime = new ThreadLocal<>();

    /**
     * 定义切点：路径表达式方式
     * 第一个*：表示任意访问修饰符和返回类型
     * 第二个*：表示包下的任意类
     * 第三个*：表示任意方法
     * ..:表示任意参数类型和个数
     */
    @Pointcut("execution(* com.king.controller.*.*(..))")
    public void pointCut() {
    }


    @Before("pointCut()")   // 方法执行前执行的通知
    public void before(JoinPoint joinPoint) {
        Object target = joinPoint.getTarget();
        System.out.println(target);

        String className = joinPoint.getTarget().getClass().getName();
        System.out.println("className = " + className);

        System.out.println("====Before====");
    }

    @AfterReturning("pointCut()")   // 方法正常执行后执行的通知
    public void afterReturning(JoinPoint joinPoint) {
        System.out.println("====AfterReturning====");
        //1.获取切入点所在目标对象
        Object targetObj =joinPoint.getTarget();
        System.out.println(targetObj.getClass().getName());
        // 2.获取切入点方法的名字
        String methodName = joinPoint.getSignature().getName();
        System.out.println("切入方法名字："+methodName);
        // 3. 获取方法上的注解
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        if (method != null)
        {
            SysLog apiLog=  method.getAnnotation(SysLog.class);
            System.out.println("切入方法注解的title:"+apiLog.value());
        }
        //4. 获取方法的参数
        Object[] args = joinPoint.getArgs();
        for(Object o :args){
            System.out.println("切入方法的参数："+o);
        }

    }

    @AfterThrowing("pointCut()")    // 方法异常后执行的通知
    public void afterThrowing() {
        System.out.println("====AfterThrowing====");
    }

    @After("pointCut()")    // 方法正常或异常都会执行的通知
    public void after() {
        System.out.println("====After====");
    }


    /**
     * 环绕通知
     *
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    @Around("pointCut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        try {
            System.out.println("====环绕通知开始====");
            // 执行目标方法(如果存在前置后置通知也会执行)
            Object proceed = joinPoint.proceed();
            System.out.println("====环绕通知结束====");
            return proceed;
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            throw new RuntimeException(throwable);
        }
    }

    @Around("@annotation(sysLog)")
    public Object around(ProceedingJoinPoint joinPoint, SysLog sysLog) {
        try {
            System.out.println("====环绕通知开始====");
            String value = sysLog.value();
            System.out.println("获取注解中属性的值：" + value);
            //执行目标方法(如果存在前置后置通知也会执行)
            Object proceed = joinPoint.proceed();
            System.out.println("====环绕通知结束====");
            return proceed;
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            throw new RuntimeException(throwable);
        }
    }


}
